package models

import (
	"fmt"
	"time"

	"github.com/beego/beego/v2/client/orm"
)

// BalanceLog 会员余额变动记录模型
type BalanceLog struct {
	BaseModel
	MemberId      int64   `orm:"index" json:"member_id"`                       // 会员ID
	Amount        float64 `orm:"digits(10);decimals(2)" json:"amount"`         // 变动金额，正数为增加，负数为减少
	Type          int8    `orm:"default(1)" json:"type"`                       // 变动类型：1:充值, 2:消费, 3:退款, 4:管理员调整
	OrderNo       string  `orm:"size(64)" json:"order_no"`                     // 关联订单号
	TransactionNo string  `orm:"size(64)" json:"transaction_no"`               // 关联交易流水号
	Description   string  `orm:"size(255)" json:"description"`                 // 变动描述
	Operator      string  `orm:"size(64)" json:"operator"`                     // 操作人
	BeforeBalance float64 `orm:"digits(10);decimals(2)" json:"before_balance"` // 变动前余额
	AfterBalance  float64 `orm:"digits(10);decimals(2)" json:"after_balance"`  // 变动后余额
}

// TableName 设置表名
func (b *BalanceLog) TableName() string {
	return "ss_balance_log"
}

// GetBalanceLogById 根据ID获取余额变动记录
func GetBalanceLogById(id int64, franchiseId int64) (*BalanceLog, error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(BalanceLog)).Filter("id", id).Filter("is_deleted", 0)

	// 加盟商过滤
	if franchiseId > 0 {
		// 获取该加盟商下的所有会员ID
		var memberIds orm.ParamsList
		_, err := o.QueryTable(new(Member)).
			Filter("franchise_id", franchiseId).
			Filter("is_deleted", 0).
			ValuesFlat(&memberIds, "id")
		if err != nil {
			return nil, err
		}
		if len(memberIds) > 0 {
			qs = qs.Filter("member_id__in", memberIds)
		}
	}

	balanceLog := &BalanceLog{}
	err := qs.One(balanceLog)
	return balanceLog, err
}

// GetBalanceLogList 获取余额变动记录列表
func GetBalanceLogList(page, pageSize int, filters map[string]interface{}) ([]*BalanceLog, int64, error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(BalanceLog))

	// 应用过滤条件
	if memberId, ok := filters["member_id"].(int64); ok {
		qs = qs.Filter("member_id", memberId)
	}

	if logType, ok := filters["type"].(int8); ok {
		qs = qs.Filter("type", logType)
	}

	if orderNo, ok := filters["order_no"].(string); ok && orderNo != "" {
		qs = qs.Filter("order_no", orderNo)
	}

	// 余额大于某值
	if balanceGt, ok := filters["balance_gt"].(float64); ok {
		qs = qs.Filter("balance__gt", balanceGt)
	}

	// 余额小于某值
	if balanceLt, ok := filters["balance_lt"].(float64); ok {
		qs = qs.Filter("balance__lt", balanceLt)
	}

	// 时间范围过滤
	if startTime, ok := filters["start_time"].(int64); ok {
		qs = qs.Filter("created_at__gte", startTime)
	}

	if endTime, ok := filters["end_time"].(int64); ok {
		qs = qs.Filter("created_at__lte", endTime)
	}

	// 加盟商过滤
	if franchiseId, ok := filters["franchise_id"].(int64); ok && franchiseId > 0 {
		// 获取该加盟商下的所有会员ID
		var memberIds orm.ParamsList
		_, err := o.QueryTable(new(Member)).
			Filter("franchise_id", franchiseId).
			Filter("is_deleted", 0).
			ValuesFlat(&memberIds, "id")
		if err != nil {
			return nil, 0, err
		}
		if len(memberIds) > 0 {
			qs = qs.Filter("member_id__in", memberIds)
		}
	}

	// 排除已删除的记录
	qs = qs.Filter("is_deleted", 0)

	// 获取总数
	total, _ := qs.Count()

	// 分页查询
	var balanceLogs []*BalanceLog
	_, err := qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&balanceLogs)

	return balanceLogs, total, err
}

// CreateBalanceLog 创建余额变动记录
func CreateBalanceLog(balanceLog *BalanceLog, franchiseId int64) (int64, error) {
	o := orm.NewOrm()

	// 验证会员是否属于该加盟商
	if franchiseId > 0 {
		qs := o.QueryTable(new(Member)).
			Filter("id", balanceLog.MemberId).
			Filter("franchise_id", franchiseId).
			Filter("is_deleted", 0)

		exists := qs.Exist()
		if !exists {
			return 0, fmt.Errorf("会员不属于该加盟商")
		}
	}

	id, err := o.Insert(balanceLog)
	return id, err
}

// UpdateMemberBalance 更新会员余额并记录
func UpdateMemberBalance(memberId int64, amount float64, logType int8, orderNo, transactionNo, description, operator string, franchiseId int64) error {
	// 开启事务
	o := orm.NewOrm()
	tx, err := o.Begin()
	if err != nil {
		return err
	}

	// 获取会员信息
	qs := o.QueryTable(new(Member)).Filter("id", memberId).Filter("is_deleted", 0)

	// 加盟商过滤
	if franchiseId > 0 {
		qs = qs.Filter("franchise_id", franchiseId)
	}

	member := &Member{}
	err = qs.One(member)
	if err != nil {
		tx.Rollback()
		return err
	}

	// 记录变动前余额
	beforeBalance := member.Balance

	// 更新会员余额
	member.Balance += amount
	member.UpdatedAt = time.Now().Unix()
	_, err = o.Update(member, "Balance", "UpdatedAt")
	if err != nil {
		tx.Rollback()
		return err
	}

	// 创建余额变动记录
	balanceLog := &BalanceLog{
		MemberId:      memberId,
		Amount:        amount,
		Type:          logType,
		OrderNo:       orderNo,
		TransactionNo: transactionNo,
		Description:   description,
		Operator:      operator,
		BeforeBalance: beforeBalance,
		AfterBalance:  member.Balance,
	}
	balanceLog.BeforeInsert()
	_, err = o.Insert(balanceLog)
	if err != nil {
		tx.Rollback()
		return err
	}

	// 提交事务
	return tx.Commit()
}

// UpdateMemberBalanceWithLog 更新会员余额并记录
func UpdateMemberBalanceWithLog(memberId int64, amount float64, logType int8, orderNo, transactionNo, description, operator string, franchiseId int64) error {
	// 开启事务
	o := orm.NewOrm()
	tx, err := o.Begin()
	if err != nil {
		return err
	}

	// 获取会员信息
	qs := o.QueryTable(new(Member)).Filter("id", memberId).Filter("is_deleted", 0)

	// 加盟商过滤
	if franchiseId > 0 {
		qs = qs.Filter("franchise_id", franchiseId)
	}

	member := &Member{}
	err = qs.One(member)
	if err != nil {
		tx.Rollback()
		return err
	}

	// 记录变动前余额
	beforeBalance := member.Balance

	// 更新会员余额
	member.Balance += amount
	member.UpdatedAt = time.Now().Unix()
	_, err = o.Update(member, "Balance", "UpdatedAt")
	if err != nil {
		tx.Rollback()
		return err
	}

	// 创建余额变动记录
	balanceLog := &BalanceLog{
		MemberId:      memberId,
		Amount:        amount,
		Type:          logType,
		OrderNo:       orderNo,
		TransactionNo: transactionNo,
		Description:   description,
		Operator:      operator,
		BeforeBalance: beforeBalance,
		AfterBalance:  member.Balance,
	}
	balanceLog.BeforeInsert()
	_, err = o.Insert(balanceLog)
	if err != nil {
		tx.Rollback()
		return err
	}

	// 提交事务
	return tx.Commit()
}

// UpdateMemberBalanceWithLogAndFranchise 更新会员余额并记录（支持加盟商权限验证）
func UpdateMemberBalanceWithLogAndFranchise(memberId int64, amount float64, logType int8, orderNo, transactionNo, description, operator string, franchiseId int64) error {
	// 开启事务
	o := orm.NewOrm()
	tx, err := o.Begin()
	if err != nil {
		return err
	}

	// 获取会员信息
	qs := o.QueryTable(new(Member)).Filter("id", memberId).Filter("is_deleted", 0)

	// 加盟商过滤
	if franchiseId > 0 {
		qs = qs.Filter("franchise_id", franchiseId)
	}

	member := &Member{}
	err = qs.One(member)
	if err != nil {
		tx.Rollback()
		return err
	}

	// 记录变动前余额
	beforeBalance := member.Balance

	// 更新会员余额
	member.Balance += amount
	member.UpdatedAt = time.Now().Unix()
	_, err = o.Update(member, "Balance", "UpdatedAt")
	if err != nil {
		tx.Rollback()
		return err
	}

	// 创建余额变动记录
	balanceLog := &BalanceLog{
		MemberId:      memberId,
		Amount:        amount,
		Type:          logType,
		OrderNo:       orderNo,
		TransactionNo: transactionNo,
		Description:   description,
		Operator:      operator,
		BeforeBalance: beforeBalance,
		AfterBalance:  member.Balance,
	}
	balanceLog.BeforeInsert()
	_, err = o.Insert(balanceLog)
	if err != nil {
		tx.Rollback()
		return err
	}

	// 提交事务
	return tx.Commit()
}

// UpdateMemberBalanceWithLogTx 在事务中更新会员余额并记录
func UpdateMemberBalanceWithLogTx(tx orm.TxOrmer, memberId int64, amount float64, logType int8, orderNo, transactionNo, description, operator string, franchiseId int64) error {
	// 获取会员信息
	qs := tx.QueryTable(new(Member)).Filter("id", memberId).Filter("is_deleted", 0)

	// 加盟商过滤
	if franchiseId > 0 {
		qs = qs.Filter("franchise_id", franchiseId)
	}

	member := &Member{}
	err := qs.One(member)
	if err != nil {
		return err
	}

	// 记录变动前余额
	beforeBalance := member.Balance

	// 更新会员余额
	member.Balance += amount
	member.UpdatedAt = time.Now().Unix()
	_, err = tx.Update(member, "Balance", "UpdatedAt")
	if err != nil {
		return err
	}

	// 创建余额变动记录
	balanceLog := &BalanceLog{
		MemberId:      memberId,
		Amount:        amount,
		Type:          logType,
		OrderNo:       orderNo,
		TransactionNo: transactionNo,
		Description:   description,
		Operator:      operator,
		BeforeBalance: beforeBalance,
		AfterBalance:  member.Balance,
	}
	balanceLog.BeforeInsert()
	_, err = tx.Insert(balanceLog)

	return err
}
